#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the version 3 of the GNU Lesser General Public License
#   as published by the Free Software Foundation.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU Lesser General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Copyright (c) NEC Deutschland GmbH, NEC HPC Europe
#
# $Id$

import os
import sys
import time


__all__ = [ "DatabaseDaemon" ]


MAXFD = 1024
# Note: MUST have "log" extension, since those files are ignored by fs marshaller
LOGFILE = "daemon.log"


class DatabaseDaemon:
    """
    This class provides mechanisms to run as a daemon and to run as a
    stand alone program.
    This program runs on a per Metric basis and accepts a list of
    files that will be condensed.
    Since logging to the standard streams is not possible from within
    a daemon process a log file will be created in the directory path
    of the particular Metric.
    Limitation: A new daemon for the same metric should not be started
    while another daemon is running. Usually this should not be the
    case anyway.
    """
    @staticmethod
    def daemon( int_file_list ):
        """
        This function will be run in the daemon process.
        """
        import logging
        from aggmon.databases.metric.rrd import RRD
        dir = os.path.dirname( int_file_list[0] )
        # Note: basicConfig only works if there have been no log outputs before!
        logpath = os.path.join( dir, LOGFILE )
        logging.basicConfig( filename=logpath, level=logging.DEBUG )
        t_s = time.time()
        t = time.gmtime( t_s )
        t_str = "%d, %02d.%02d.%d %02d:%02d:%02d" % (long( t_s ), \
                t.tm_mday, t.tm_mon, t.tm_year, t.tm_hour, t.tm_min, t.tm_sec)
        logging.info( "daemon started on: " + t_str )
        logging.debug( "file_list: " + str( int_file_list ) )
        rrd = RRD( dir, keep_exact=None, rotation_period=None )
        rrd.cascade( int_file_list )
        logging.shutdown()
        logging.debug( "daemon finished.\n" )
        return 0

    @staticmethod
    def createDaemon( rrd_instance ):
        """
        Create new process and daemonize it via double fork.
        """

        try:
            pid = os.fork()
        except OSError, e:
            raise Exception, "Can't fork %s [%d]" % (e.strerror, e.errno)

        if ( pid != 0 ):
            return

        os.setsid()
        import signal
        signal.signal( signal.SIGHUP, signal.SIG_IGN )
        try:
            pid = os.fork()
        except OSError, e:
            raise Exception, "Can't fork %s [%d]" % (e.strerror, e.errno)

        if (pid != 0):
            os._exit( 0 )

        os.chdir( "/" )
        os.umask( 0 )

        import resource
        maxfd = resource.getrlimit( resource.RLIMIT_NOFILE )[1]
        if ( maxfd == resource.RLIM_INFINITY ):
            maxfd = MAXFD

        for fd in range( 0, maxfd ):
            try:
                os.close( fd )
            except OSError:
                pass

        os.open( os.devnull, os.O_RDWR )

        os.dup2( 0, 1 )
        os.dup2( 0, 2 )

        #sys.exit( DatabaseDaemon.daemon( rrd_instance ) )
        DatabaseDaemon.daemon( rrd_instance )

if __name__ == "__main__":
    """
    Daemon can run as stand alone program. Provide path to metric
    database as argument.
    """
    from aggmon.databases.metric.rrd import RRD
    rrd = RRD( sys.argv[1], keep_exact=None, rotation_period=None )
    if rrd.number_of_files_to_condense() > 0:
        int_file_list = rrd.get_files_to_condense()
        DatabaseDaemon.daemon( int_file_list )
